//
//  CLBookChapter.swift
//  CJBookReader
//
//  Created by colin on 2019/3/22.
//  Copyright © 2019 lidi. All rights reserved.
//

class CLBookChapter:Codable {
    /// 资源id
    var goods_id = 0
    /// 章节id
    var id = 0
    /// 章节名称
    var name = ""
    
    var create_time = 0
    var pid = 0
    var start_page = 0
    var code = ""
    var end_page = ""
    var format = ".epub"
    var path = ""
    var pname = ""
    var purl = ""
    var url = ""
    
    var content = ""
    
    /// 初始化
    init(chapterJSON:JSONObject?) {
        if let value = chapterJSON?["goods_id"] as? Int { self.goods_id = value }
        if let value = chapterJSON?["id"] as? Int { self.id = value }
        if let value = chapterJSON?["name"] as? String { self.name = value }
        
        if let value = chapterJSON?["create_time"] as? Int { self.create_time = value }
        if let value = chapterJSON?["pid"] as? Int { self.pid = value }
        if let value = chapterJSON?["start_page"] as? Int { self.start_page = value }
        if let value = chapterJSON?["code"] as? String { self.code = value }
        if let value = chapterJSON?["end_page"] as? String { self.end_page = value }
        if let value = chapterJSON?["format"] as? String { self.format = value }
        if let value = chapterJSON?["path"] as? String { self.path = value }
        if let value = chapterJSON?["pname"] as? String { self.pname = value }
        if let value = chapterJSON?["purl"] as? String { self.purl = value }
        if let value = chapterJSON?["url"] as? String { self.url = value }
    }
    
    var pages:Int {
        return self.chapterFrames.count
    }
    var contents:[Content] { return self.epubContents }
    private var epubContents = [Content]()
    private var chapterFrames = [CTFrame]() // 分页

    // MARK: -- Codable
    private enum CodingKeys:String,CodingKey {
        case goods_id, id, name, create_time, pid, start_page, code, end_page, format, path, pname, purl, url, content
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(self.goods_id, forKey: .goods_id)
        try container.encode(self.id, forKey: .id)
        try container.encode(self.name, forKey: .name)
        try container.encode(self.create_time, forKey: .create_time)
        try container.encode(self.pid, forKey: .pid)
        try container.encode(self.start_page, forKey: .start_page)
        try container.encode(self.code, forKey: .code)
        try container.encode(self.end_page, forKey: .end_page)
        try container.encode(self.format, forKey: .format)
        try container.encode(self.path, forKey: .path)
        try container.encode(self.pname, forKey: .pname)
        try container.encode(self.purl, forKey: .purl)
        try container.encode(self.url, forKey: .url)
        try container.encode(self.content, forKey: .content)
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        for key in container.allKeys {
            switch key {
            case .goods_id:
                self.goods_id = try container.decodeNil(forKey: .goods_id) ? 0 : try container.decode(Int.self, forKey: .goods_id)
            case .id:
                self.id = try container.decodeNil(forKey: .id) ? 0 : try container.decode(Int.self, forKey: .id)
            case .name:
                self.name = try container.decodeNil(forKey: .name) ? "" : try container.decode(String.self, forKey: .name)
            case .create_time:
                self.create_time = try container.decodeNil(forKey: .create_time) ? 0 : try container.decode(Int.self, forKey: .create_time)
            case .pid:
                self.pid = try container.decodeNil(forKey: .pid) ? 0 : try container.decode(Int.self, forKey: .pid)
            case .start_page:
                self.start_page = try container.decodeNil(forKey: .start_page) ? 0 : try container.decode(Int.self, forKey: .start_page)
            case .code:
                self.code = try container.decodeNil(forKey: .code) ? "" : try container.decode(String.self, forKey: .code)
            case .end_page:
                self.end_page = try container.decodeNil(forKey: .end_page) ? "" : try container.decode(String.self, forKey: .end_page)
            case .format:
                self.format = try container.decodeNil(forKey: .format) ? "" : try container.decode(String.self, forKey: .format)
            case .path:
                self.path = try container.decodeNil(forKey: .path) ? "" : try container.decode(String.self, forKey: .path)
            case .pname:
                self.pname = try container.decodeNil(forKey: .pname) ? "" : try container.decode(String.self, forKey: .pname)
            case .purl:
                self.purl = try container.decodeNil(forKey: .purl) ? "" : try container.decode(String.self, forKey: .purl)
            case .url:
                self.url = try container.decodeNil(forKey: .url) ? "" : try container.decode(String.self, forKey: .url)
            case .content:
                self.content = try container.decodeNil(forKey: .content) ? "" : try container.decode(String.self, forKey: .content)
            }
            
        }
        
        // 重新处理epub内容
        self.setEpubContents()
        // 重新分页
        self.reload()
    }
}

extension CLBookChapter {
    
    class Content {}
    class Image : Content {
        var url = "" //图片链接
        var size = CGSize.zero // 图片大小
        var imageRect = CGRect.zero //图片位置
        var position = 0
    }
    
    class Text : Content {
        var content = ""
        var width:CGFloat = 0
        var height:CGFloat = 0
    }
    
    // 设置内容
    func setContent(html:String) {
        if let plainText = NSString(string: html).convertingHTMLToPlainText() {
            let filterText = plainText.filterTxt()
            self.content = filterText
        } else {
            self.content = ""
        }
    }
    
    // 转换HTML
    func setEpubContents() {
        let scanner = Scanner(string: self.content)
        var chapterContents = [Content]()
        
        var targetContent = ""
        
        while !scanner.isAtEnd {
            if scanner.scanString("<img>", into: nil) {
                
                var imageUrl:NSString? = ""
                scanner.scanUpTo("</img>", into: &imageUrl)
                
                if let url = imageUrl {
                    let imageUrlString = String(url)
                    let image = Image()
                    
                    //获取图片大小
                    if let imageSize = CJImageDownloader.shared.fetchImage(imageUrl: imageUrlString)?.size {
                        
                        let readViewSize = DZMReadView.readFrame.size
                        
                        var width = imageSize.width
                        var height = imageSize.height
                        
                        if width > readViewSize.width {
                            height = height * (readViewSize.width / width)
                            width = readViewSize.width
                        }
                        
                        if height > readViewSize.height {
                            width = width * (readViewSize.height / height)
                            height = readViewSize.height
                        }
                        
                        image.size = CGSize(width: width, height: height)
                    }
                    
                    image.url = imageUrlString
                    image.position = targetContent.length
                    
                    chapterContents.append(image)
                }
                
                scanner.scanString("</img>", into: nil)
                
            } else {
                var text:NSString? = ""
                if scanner.scanUpTo("<img>", into: &text) {
                    if let text_ = text {
                        let textContent = String(text_)
                        let stringContent = Text()
                        stringContent.content = textContent
                        chapterContents.append(stringContent)
                        
                        targetContent += textContent
                    }
                }
            }
        }
        
        self.epubContents = chapterContents
    }
}

extension CLBookChapter {
    
    // 重新分页
    func reload() {
        self.paginate(bounds: DZMReadView.readFrame)
    }
    
    //分页
    private func paginate(bounds:CGRect) {
        let attrString = NSMutableAttributedString()
        for child in self.contents {
            
            if let con = child as? Text {
                //解析文本
                let attr = CLReadConfigure.shared.readAttribute
                let subString = NSMutableAttributedString(string: con.content, attributes: attr)
                attrString.append(subString)
            }
            
            if let con = child as? Image {
                
                //解析图片
                var imageCallback = CTRunDelegateCallbacks(version: kCTRunDelegateVersion1, dealloc: { (refCon) in
                    
                }, getAscent: {(refCon) -> CGFloat in
                    //高度
                    let opaquePtr = OpaquePointer(refCon)
                    let contextPtr = UnsafeMutablePointer<Image>(opaquePtr)
                    let img = contextPtr.pointee
                    let height = img.size.height
                    return height
                }, getDescent: { (refCon) -> CGFloat in
                    return 0  //返回底部距离
                }, getWidth: { (refCon) -> CGFloat in
                    //宽度
                    let opaquePtr = OpaquePointer(refCon)
                    let contextPtr = UnsafeMutablePointer<Image>(opaquePtr)
                    let img = contextPtr.pointee
                    let width = img.size.width
                    return width
                })
                
                var contentInfo = con
                
                let runDelegate = CTRunDelegateCreate(&imageCallback, &contentInfo)!
                let subString = NSMutableAttributedString(string: "\n")  // 空格用于给图片留位置
                subString.addAttribute(kCTRunDelegateAttributeName as NSAttributedString.Key, value: runDelegate, range: NSMakeRange(0, 1))  //rundelegate  占一个位置
                subString.addAttribute(NSAttributedString.Key(rawValue: "imagePath"), value: contentInfo.url, range: NSMakeRange(0, 1))//添加属性，在CTRun中可以识别出这个字符是图片
                attrString.append(subString)
            }
        }
        
        let setterRef = CTFramesetterCreateWithAttributedString(attrString)
        let pathRef = CGPath(rect: bounds, transform: nil)
        
        let frameRef = CTFramesetterCreateFrame(setterRef, CFRange(location: 0, length: 0), pathRef, nil)
        
        var rang1 = CTFrameGetVisibleStringRange(frameRef)
        let rang2 = CTFrameGetStringRange(frameRef)
        
        var frames = [CTFrame]()
        
        // var subContents = [String]() //记录书签使用
        // let normalString = attrString.string //记录书签使用
        
        if rang1.length + rang1.location == rang2.length + rang2.location {
            let subFrameRef = CTFramesetterCreateFrame(setterRef,CFRange(location: rang1.location, length: 0), pathRef, nil)
            let range = CTFrameGetVisibleStringRange(subFrameRef)
            rang1 = CFRange(location: range.location + range.length,length: 0)
            frames.append(subFrameRef)
            
            // let subString = normalString.substring(NSRange(location: range.location, length: range.length))//记录书签使用
            // subContents.append(subString) //记录书签使用
        } else {
            while rang1.length + rang1.location < rang2.location + rang2.length {
                let subFrameRef = CTFramesetterCreateFrame(setterRef,CFRange(location: rang1.location, length: 0), pathRef, nil)
                let range = CTFrameGetVisibleStringRange(subFrameRef)
                rang1 = CFRange(location: range.location + range.length,length: 0)
                frames.append(subFrameRef)
                
                // let subString = normalString.substring(NSRange(location: range.location, length: range.length))//记录书签使用
                // subContents.append(subString) //记录书签使用
            }
        }
        
        // self.subStrings = subContents //记录书签使用
        
        self.chapterFrames = frames
    }
}

extension CLBookChapter {
    //获取frame
    func frame(page:Int) -> CTFrame? {
        if page >= 0 && page < self.chapterFrames.count {
            return self.chapterFrames[page]
        } else {
            return nil
        }
    }
}

extension Sequence where Self.Element : CLBookChapter {
    func chapter(id:Int) -> Self.Element? {
        let result = self.filter { (item) -> Bool in
            if item.id == id {
                return true
            } else {
                return false
            }
        }
        if !result.isEmpty {
            return result[0]
        } else {
            return nil
        }
    }
}

